/*
 * BSM6.0
 *
 * Copyright 2012-2013 (C) SINODATA CO., LTD. All Rights Reserved.
 */
package com.sinodata.bsm.cicp.task;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import com.sinodata.bsm.cicp.cache.CacheFactory;
import com.sinodata.bsm.cicp.cache.CollectFieldCache;
import com.sinodata.bsm.cicp.cache.CollectParamCache;
import com.sinodata.bsm.cicp.cache.ResAttrValCache;
import com.sinodata.bsm.cicp.cache.ResCache;
import com.sinodata.bsm.cicp.cache.ResRelationCache;
import com.sinodata.bsm.cicp.collector.Collector;
import com.sinodata.bsm.cicp.service.ServiceFactory;
import com.sinodata.bsm.common.vo.CollectField;
import com.sinodata.bsm.common.vo.CollectParam;
import com.sinodata.bsm.common.vo.CollectTask;
import com.sinodata.bsm.common.vo.Res;
import com.sinodata.bsm.common.vo.ResAttrVal;
import com.sinodata.bsm.common.vo.ResRelation;

/**
 * <p>
 * Description: 采集程序实例的工厂类，为每一个采集任务实例化一个采集程序实例
 * </p>
 *
 * @author tangli
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-5-23 上午10:28:18          tangli         1.0         To create
 * </p>
 *
 * @since 
 * @see     
 */
public class CollectorFactory {
    private static Logger logger = Logger.getLogger(CollectorFactory.class);
    private static Map<String, Collector> pool = new HashMap<String, Collector>();
    private static CollectParamCache collectParamCache = (CollectParamCache) CacheFactory.getCache(CollectParamCache.class);
    private static CollectFieldCache collectFieldCache = (CollectFieldCache) CacheFactory.getCache(CollectFieldCache.class);
    private static ResAttrValCache resAttrValCache = (ResAttrValCache) CacheFactory.getCache(ResAttrValCache.class);
    private static ResCache resCache = (ResCache) CacheFactory.getCache(ResCache.class);
    private static ResRelationCache resRelationCache = (ResRelationCache) CacheFactory.getCache(ResRelationCache.class);

    public synchronized static Collector getCollector(Long resId, Long taskId) {
        String key = resId + "_" + taskId;
        Collector collector = null;
        if (pool.containsKey(key)) {
            collector = pool.get(key);
        } else {
            CollectTask task = ServiceFactory.getCollectorService().getCollectTask(taskId);
            if (task != null) {
                String className = ServiceFactory.getCollectorService().getCollector(task.getCollectorId()).getClassName();
                try {
                    collector = (Collector) Class.forName(className).newInstance();
                    pool.put(key, collector);
                } catch (Exception e) {
                    logger.error("failed to new instance:" + className, e);
                    return null;
                }
            }
        }
        wrap(collector, resId, taskId);
        return collector;
    }

    /**
     * 设置采集任务的参数和指标映射
     * @param collector
     * @param resId
     * @param taskId
     */
    private synchronized static void wrap(Collector collector, Long resId, Long taskId) {
        Map<String, String> paramMap = new HashMap<String, String>();
        List<CollectParam> params = collectParamCache.getCollectParamsByTaskId(taskId);
        if (params != null) {
            for (CollectParam collectParam : params) {
                String paramName = collectParam.getParamName();
                String paramValue = collectParam.getParamValue();
                paramMap.put(paramName, replaceAttributeValue(paramValue, resId));
            }
        }

        collector.setParamMap(paramMap);

        Map<Long, String> propMap = new HashMap<Long, String>();
        List<CollectField> fields = collectFieldCache.getCollectFieldsByTaskId(taskId);
        if (fields != null) {
            for (CollectField field : fields) {
                Long propId = field.getProp();
                String value = field.getFieldName();
                propMap.put(propId, value);
            }
        }
        collector.setPropMap(propMap);
    }

    private static String replaceAttributeValue(String str, Long resId) {
        if (str == null || str.length() == 0) {
            return str;
        }
        Pattern pattern = Pattern.compile("\\$\\{(\\d+)\\}");
        Matcher matcher = pattern.matcher(str);
        while (matcher.find()) {
            Long attrId = Long.parseLong(matcher.group(1).trim());
            String attrVal = getAttributeValue(resId, attrId);
            //由于attrVal中可能含有多个$符号，在使用replaceAll()时会报错，所以用下面的代码替换
            //begin 
            if (attrVal == null) {
                return null;
            }
            if (attrVal.contains("$")) {
                String regex = "(.*)\\$(.*)";
                Pattern pattern2 = Pattern.compile(regex);
                Matcher matcher2 = pattern2.matcher(attrVal);
                while (true) {
                    if (matcher2.find()) {
                        attrVal = matcher2.group(1) + " <@> " + matcher2.group(2);
                        matcher2 = pattern2.matcher(attrVal);
                    } else {
                        break;
                    }
                }
                attrVal = attrVal.replace(" <@> ", "\\$");
            }//end
            str = str.replaceAll("\\$\\{" + attrId + "\\}", attrVal);
        }
        return str;
    }

    private static String getAttributeValue(Long resId, Long attrId) {
        ResAttrVal attrVal = resAttrValCache.get(resId, attrId);
        if (attrVal != null) {
            return attrVal.getAttrValue() == null ? "" : attrVal.getAttrValue();
        }
        List<Res> parents = parents(resId);
        for (Res res : parents) {
            attrVal = resAttrValCache.get(res.getId(), attrId);
            if (attrVal != null) {
                return attrVal.getAttrValue() == null ? "" : attrVal.getAttrValue();
            }
        }
        for (Res res : parents) {
            List<Res> uparents = parents(res.getId());
            for (Res res2 : uparents) {
                attrVal = resAttrValCache.get(res2.getId(), attrId);
                if (attrVal != null) {
                    return attrVal.getAttrValue() == null ? "" : attrVal.getAttrValue();
                }
            }
        }
        return null;
    }

    private static List<Res> parents(Long resId) {
        return from(resId, 101L);
    }

    private static List<Res> from(Long resId, Long relationTypeId) {
        List<ResRelation> relations = resRelationCache.getResRelationsOfRes(resId);
        List<Res> resources = new ArrayList<Res>();
        if (relations != null) {
            for (ResRelation resRelation : relations) {
                if (resRelation.getEndId().longValue() == resId.longValue()) {
                    boolean isRel = false;
                    if (relationTypeId.longValue() == resRelation.getRelationTypeId().longValue()) {
                        isRel = true;
                    }
                    if (!isRel) {
                        continue;
                    }
                    Res res = resCache.get(resRelation.getStartId());
                    if (res != null && !resources.contains(res)) {
                        resources.add(res);
                    }
                }
            }
        }
        return resources;
    }
}
